﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Estimate.Common.DBFieldTypes;
using Estimate.Common.Repository;
using Estimate.Common.Entity;
using Estimate.Common.Estimate;
using Estimate.Common.Estimate.EstimateValue;
using Newtonsoft.Json;

namespace Estimate.Reports
{
    /// <summary>
    /// 预报员排名报表
    /// </summary>
    public class IndividualRankReport
    {
        #region 变量与对象
        private FullInfoReport WaterAmountLevelScoreReport;// 计算晴雨及一般降水对象
        private FullInfoReport WaterAmountLevelSkillReport;//计算24小时晴雨及一般降水技巧
        private FullInfoReport WaterAmountLevelSkillStandardReport;//计算24小时晴雨及一般降水技巧的标准值
        private FullInfoReport TempScoreReport;//计算气温预报准确率
        private FullInfoReport TempSkillReport;//计算气温预报技巧值
        private FullInfoReport TempSkillStandardReport;//计算气温预报技巧的标准值

        private Dictionary<string,List< string>> Forecasters = null;//存放从系统前端传过来的预报员，字典key为站点编号
        ForecasterRankResult Result = new ForecasterRankResult();//排名结果
 
        protected string _connectionString;
        ExecutionStatus exeStatus = null;//程序执行状态

        public double Proportion = 0.67;//样本比例
        #endregion

        #region 构造函数
        /// <summary>
        /// 预报员排名报表类构造函数,默认所有预报员参加排名
        /// </summary>
        /// <param name="connectionString"></param>
        public IndividualRankReport(string connectionString)
        {
            _connectionString = connectionString;
        }

        /// <summary>
        /// 预报员排名报表类构造函数，指定预报员参与排名
        /// </summary>
        /// <param name="forecasters">系统前端传递过来的预报员</param>
        /// <param name="connectionString"></param>
        /// <param name="tid">程序执行任务号</param>
        public IndividualRankReport(string forecasters, string connectionString,double proportion, string tid)
        {
            //由于 58248 镇江站已经取消，使用的是58252. 但是预报数据中一直使用的是58248,所以将镇江站手动修正为58248
            forecasters = forecasters.Replace("58252", "58248");

            Proportion = proportion;
            _connectionString = connectionString;

            if (tid != "") exeStatus = new ExecutionStatus(tid);

            //分割预报员字符串，将结果存入Forecasters字典
            Forecasters = new Dictionary<string,List< string>>();
            foreach (string forecaster in forecasters.Split(','))
            {
                string[] strs = forecaster.Replace("'", "").Split('_');
                if (strs.Length < 2) continue;
                if (!Forecasters.Keys.Contains(strs[0]))
                    Forecasters.Add(strs[0],new List<string>());
                Forecasters[strs[0]].Add( strs[1]);
            }

        }
        #endregion

        #region 初始化，检索、筛选预报员排班表
        /// <summary>
        /// 初始化，检索、筛选预报员排班表
        /// </summary>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <param name="clocks"></param>
        /// <param name="sendpoints"></param>
        protected List<ScheduleEntity> Initial(DateTime beginDate, DateTime endDate, ForeSendpointType[] sendpoints)
        {
            #region 检索出地区名称列表
            StationMatchRepository stationMatchRepository = new StationMatchRepository(_connectionString);
            Dictionary<string, string> AreaStations = stationMatchRepository.GetAllNameStationDictionary(StationMatchStationsType.area, StationMatchExtralType.cz);
            #endregion

            #region 检索出时间段内排班表记录
            SendpointToClock parser = new SendpointToClock();
            ForeClockType[] clocks = parser.GetClockArrayWithSendPointArray(sendpoints);
            ScheduleRepository scheduleRepository = new ScheduleRepository(_connectionString);
            ScheduleEntity[] Schedules = scheduleRepository.GetSchedulesWithDateRange(beginDate, endDate, clocks, sendpoints);
            #endregion

            #region 如果Forecasters有值则根据预报员列表筛选排班表，否则不筛选(计算所有预报排名)

            List<ScheduleEntity> IndividualSchedules = new List<ScheduleEntity>();

            foreach(ScheduleEntity schedule in Schedules)
            {
                //由于 58248 镇江站已经取消，使用的是58252. 但是预报数据中一直使用的是58248,所以将镇江站手动修正为58248
                if (schedule.Station == "58252")
                    schedule.Station = "58248";

                if (Forecasters != null && Forecasters.Count > 0)
                {
                    if (!Forecasters.Keys.Contains(schedule.Station))
                        continue;

                    schedule.ForecastNumber = string.Format(",{0},", schedule.ForecastNumber);
                    foreach (string fnum in Forecasters[schedule.Station])
                    {
                        if (schedule.ForecastNumber.Contains(string.Format(",{0},", int.Parse(fnum).ToString())))
                        {
                            ScheduleEntity se = new ScheduleEntity();
                            se.Copy(schedule);
                            se.ForecastNumber = fnum;
                            IndividualSchedules.Add(se);
                        }
                    }
                }
                else
                {
                    foreach (string fnum in schedule.ForecastNumber.Split(','))
                    {
                        ScheduleEntity se = new ScheduleEntity();
                        se.Copy(schedule);
                        se.ForecastNumber = fnum;
                        IndividualSchedules.Add(se);
                    }
                }

               
            }
            #endregion

            #region 找到每条排班表记录中站点的相应的地区列表记录，并赋值
            foreach (ScheduleEntity schedule in IndividualSchedules)
            {
                foreach (KeyValuePair<string, string> station in AreaStations)
                {
                    if (station.Value.Contains(schedule.Station))
                    {
                        schedule.Stations = station.Value;
                        schedule.StationName = station.Key;
                        break;
                    }
                }
            }
            #endregion

            return IndividualSchedules;

        }
        #endregion

        #region  数据准备并计算
        public void PrepareData(DateTime beginDate, DateTime endDate, ForeSemiType semitype)
        {
            try
            {
                if (exeStatus != null) exeStatus.SetMessage("Initial", "正在准备...");

                #region 晴雨预报正确率、一般降水、暴雨暴雪以上初始化
                //ForeSpanType[] spans1 = new ForeSpanType[] { ForeSpanType.FD00_12, ForeSpanType.FD12_24, ForeSpanType.FD24_36, ForeSpanType.FD36_48, ForeSpanType.FD48_60, ForeSpanType.FD60_72, ForeSpanType.FD72_84, ForeSpanType.FD84_96, ForeSpanType.FD96_108, ForeSpanType.FD96_120 };
                ForeSpanType[] spans1 = new ForeSpanType[] { ForeSpanType.FD00_24, ForeSpanType.FD24_48, ForeSpanType.FD48_72, ForeSpanType.FD72_96, ForeSpanType.FD96_120 };
                ForeSendpointType[] sendpoints1 = new ForeSendpointType[] { ForeSendpointType.H06, ForeSendpointType.H16 };
                List<ScheduleEntity> IndividualSchedules1 = Initial(beginDate, endDate, sendpoints1);
                WaterAmountLevelScoreReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.NormalCityForeRepository(_connectionString), IndividualSchedules1);
                WaterAmountLevelScoreReport.CulculateWeatherScore = true;
                WaterAmountLevelScoreReport.CulculateWaterfallLevelWaterScore = true;
                WaterAmountLevelScoreReport.CulculateWaterfallLevelSplitFD24ToFD12 = true;
                WaterAmountLevelScoreReport.CulculateWaterfallAmountWaterScore = true;
                WaterAmountLevelScoreReport.CulculateWaterfallAmountSplitFD24ToFD12 = true;
                WaterAmountLevelScoreReport.ExeStatus = exeStatus;
                #endregion

                #region 最高温及最低温预报准确率初始化
                ForeSpanType[] spans2 = new ForeSpanType[] { ForeSpanType.FD00_24, ForeSpanType.FD24_48, ForeSpanType.FD48_72, ForeSpanType.FD72_96, ForeSpanType.FD96_120 };
                ForeSendpointType[] sendpoints2 = new ForeSendpointType[] { ForeSendpointType.H06, ForeSendpointType.H10, ForeSendpointType.H16 };
                List<ScheduleEntity> IndividualSchedules2 = Initial(beginDate, endDate, sendpoints2);
                TempScoreReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.NormalCityForeRepository(_connectionString), IndividualSchedules2);
                TempScoreReport.CulculateMaxTempScore = true;
                TempScoreReport.CulculateMinTempScore = true;
                TempScoreReport.ExeStatus = exeStatus;
                #endregion

                #region 24小时晴雨技巧值、24小时一般降水技巧值、24小时暴雨暴雪以上技巧值初始化
                //ForeSpanType[] spans3 = new ForeSpanType[] { ForeSpanType.FD00_12, ForeSpanType.FD12_24 };
                ForeSpanType[] spans3 = new ForeSpanType[] { ForeSpanType.FD00_24 };
                ForeSendpointType[] sendpoints3 = new ForeSendpointType[] { ForeSendpointType.H06 };
                List<ScheduleEntity> IndividualSchedules3 = Initial(beginDate, endDate, sendpoints3);
                WaterAmountLevelSkillReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.NormalCityForeRepository(_connectionString), IndividualSchedules3);
                WaterAmountLevelSkillReport.CulculateWeatherScore = true;
                WaterAmountLevelSkillReport.CulculateWaterfallLevelWaterScore = true;
                WaterAmountLevelSkillReport.CulculateWaterfallLevelSplitFD24ToFD12 = true;
                WaterAmountLevelSkillReport.CulculateWaterfallAmountWaterScore = true;
                WaterAmountLevelSkillReport.CulculateWaterfallAmountSplitFD24ToFD12 = true;
                WaterAmountLevelSkillReport.ExeStatus = exeStatus;

                WaterAmountLevelSkillStandardReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.ZytCityForeRepository(_connectionString), IndividualSchedules3);
                WaterAmountLevelSkillStandardReport.CulculateWeatherScore = true;
                WaterAmountLevelSkillStandardReport.CulculateWaterfallLevelWaterScore = true;
                WaterAmountLevelSkillStandardReport.CulculateWaterfallAmountWaterScore = true;
                WaterAmountLevelSkillStandardReport.ExeStatus = exeStatus;
                #endregion

                #region 24小时最高温及最低温预报技巧值初始化
                ForeSpanType[] spans4 = new ForeSpanType[] { ForeSpanType.FD00_24 };
                ForeSendpointType[] sendpoints4 = new ForeSendpointType[] { ForeSendpointType.H06 };
                List<ScheduleEntity> IndividualSchedules4 = Initial(beginDate, endDate, sendpoints4);
                TempSkillReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.NormalCityForeRepository(_connectionString), IndividualSchedules4);
                TempSkillReport.CulculateMaxTempScore = true;
                TempSkillReport.CulculateMinTempScore = true;
                TempSkillReport.ExeStatus = exeStatus;

                TempSkillStandardReport = new FullInfoReport(_connectionString, ForeRepositoryFactory.ZytCityForeRepository(_connectionString), IndividualSchedules4);
                TempSkillStandardReport.CulculateMaxTempScore = true;
                TempSkillStandardReport.CulculateMinTempScore = true;
                TempSkillStandardReport.ExeStatus = exeStatus;
                #endregion

                #region 数据准备及计算
                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("Initial");

                    exeStatus.TotalSteps = WaterAmountLevelScoreReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans1, spans1) +
                                           TempScoreReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans2, spans2) +
                                           WaterAmountLevelSkillReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans3, spans3) +
                                           WaterAmountLevelSkillStandardReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans3, spans3) +
                                           TempSkillReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans4, spans4) +
                                           TempSkillStandardReport.GetExeStatusTotalSteps(beginDate, endDate, semitype, spans4, spans4);

                    exeStatus.SetMessage("WaterAmountLevelScoreReport", "晴雨及一般降水");
                }

                WaterAmountLevelScoreReport.PrepareData(beginDate, endDate, semitype, spans1, spans1, sendpoints1);

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("WaterAmountLevelScoreReport");
                    exeStatus.SetMessage("TempScoreReport", "温度");
                }

                TempScoreReport.PrepareData(beginDate, endDate, semitype, spans2, spans2, sendpoints2);

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("TempScoreReport");
                    exeStatus.SetMessage("WaterAmountLevelSkillReport", "晴雨及一般降水技巧");
                }

                WaterAmountLevelSkillReport.PrepareData(beginDate, endDate, semitype, spans3, spans3, sendpoints3);

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("WaterAmountLevelSkillReport");
                    exeStatus.SetMessage("WaterAmountLevelSkillStandardReport", "晴雨及一般降水标准");
                }

                WaterAmountLevelSkillStandardReport.PrepareData(beginDate, endDate, semitype, spans3, spans3, sendpoints3);

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("WaterAmountLevelSkillStandardReport");
                    exeStatus.SetMessage("TempSkillReport", "气温技巧");
                }

                TempSkillReport.PrepareData(beginDate, endDate, semitype, spans4, spans4, sendpoints4);

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("TempSkillReport");
                    exeStatus.SetMessage("TempSkillStandardReport", "气温标准");
                }

                TempSkillStandardReport.PrepareData(beginDate, endDate, semitype, spans4, spans4, sendpoints4);

                if (exeStatus != null)
                    exeStatus.DeleteMessage("TempSkillStandardReport");
                #endregion

            }
            catch (Exception ex)
            {

                Result.success = false.ToString();
                Result.msg = ex.ToString();
                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("memberReportScore");
                    exeStatus.SetMessage("Error", "程序执行出错");
                }
            }
        }

        #endregion

        #region 获取首页预报员得分排名
        /// <summary>
        /// 获取首页预报员得分排名
        /// </summary>
        /// <param name="top">前top名预报员得分,top==-1表示全部</param>
        /// <returns></returns>
        public List<Dictionary<string, object>> GetForecasterRank(int top)
        {
            List<Dictionary<string, object>> TopForecasters = new List<Dictionary<string, object>>();

            List<ForecasterScore> ForecasterScoreList = GetForecasterScore();

            CulculateComposite(ForecasterScoreList);

            int FistEnd = 0;
            int SecondEnd = 0;
            SortResult(ForecasterScoreList, ref FistEnd, ref SecondEnd);

            if (top == -1 || ForecasterScoreList.Count < top)
                top = ForecasterScoreList.Count;

            for (int i = 0; i < top; i++)
            {
                Dictionary<string, object> forecaster = new Dictionary<string, object>();
                forecaster.Add("name", ForecasterScoreList[i].user);
                forecaster.Add("department", ForecasterScoreList[i].station);
                forecaster.Add("score", ForecasterScoreList[i].Composite);
                forecaster.Add("recordcount", ForecasterScoreList[i].RecordCount);

                TopForecasters.Add(forecaster);                                      
            }
            return TopForecasters;

        }

        public string GetForecasterRankDataString()
        {
            return JsonConvert.SerializeObject(GetForecasterRank(-1));
        }

        #endregion

        #region 获取预报员得分排名
        /// <summary>
        /// 获取所有预报员得分排名字符串
        /// </summary>
        /// <returns></returns>
        public string GetReportDataString()
        {
            try
            {
                if (exeStatus != null) exeStatus.SetMessage("GetReportDataString", "获取计算结果");

                List<ForecasterScore> ForecasterScoreList = GetForecasterScore();

                CulculateComposite(ForecasterScoreList);

                int FistEnd = 0;
                int SecondEnd = 0;
                SortResult(ForecasterScoreList, ref FistEnd, ref SecondEnd);
                Result.result["first_end"] = FistEnd;
                Result.result["second_end"] = SecondEnd;
                Result.result["data"] = ForecasterScoreList;

                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("GetReportDataString");
                    exeStatus.SetMessage(true, "ExecutionEnd", "执行完毕");
                }
            }
            catch (Exception ex)
            {
                Result.success = false.ToString();
                Result.msg = ex.Message;
                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("GetReportDataString");
                    exeStatus.SetMessage("Error", "执行出错");
                }
              
            }

            return JsonConvert.SerializeObject(Result).Replace("-99999.0", "'-'");
        }

        /// <summary>
        /// 获取区域预报员排名，以区域站点号为key
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> GetAreaForecasterRankData()
        {
            if (exeStatus != null) exeStatus.SetMessage("GetAreaForecasterRankData", "获取计算结果");
            //区域站点
            StationMatchRepository stationMatchRepository = new StationMatchRepository(_connectionString);
            Dictionary<string, string> stations = stationMatchRepository.GetAllNameStationDictionary(StationMatchStationsType.city, StationMatchExtralType.cz);
            //区域预报员排名结果
            Dictionary<string, string> AreaForecastersRankResult = new Dictionary<string, string>();
            //获取所有预报员得分
            List<ForecasterScore> ForecasterScoreList = GetForecasterScore();
            //按区域分别对该区域内预报员进行排名
            foreach (KeyValuePair<string, string> station in stations)
            {
                try
                {
                    List<ForecasterScore> AreaForecasterScoreList = new List<ForecasterScore>();
                    foreach (ForecasterScore score in ForecasterScoreList)
                    {
                        if (score.station == station.Key)
                            AreaForecasterScoreList.Add(score);
                    }

                    CulculateComposite(AreaForecasterScoreList);

                    //AreaForecasterScoreList.Sort(new IndividualCompositeScore());
                    int FistEnd = 0;
                    int SecondEnd = 0;
                    SortResult(AreaForecasterScoreList, ref FistEnd, ref SecondEnd);
                    Result.result["first_end"] = FistEnd;
                    Result.result["second_end"] = SecondEnd;
                    Result.result["data"] = AreaForecasterScoreList;

                    AreaForecastersRankResult.Add(station.Value, JsonConvert.SerializeObject(Result).Replace("-99999.0", "'-'"));
                }
                catch (Exception ex)
                {
                    Result.success = false.ToString();
                    Result.msg = ex.Message;
                    if (exeStatus != null)
                    {
                        exeStatus.DeleteMessage("GetAreaForecasterRankData");
                        exeStatus.SetMessage("Error", "执行出错");
                    }

                }
            }

            if (exeStatus != null)
            {
                exeStatus.DeleteMessage("GetAreaForecasterRankData");
                exeStatus.SetMessage(true, "ExecutionEnd", "执行完毕");
            }

            return AreaForecastersRankResult;
        }

        /// <summary>
        /// 计算并格式化预报员得分
        /// </summary>
        /// <returns></returns>
        private List<ForecasterScore> GetForecasterScore()
        {
            List<ForecasterScore> ScoreList = new List<ForecasterScore>();

            Dictionary<string, ForecasterScore> ForecasterScoreList = new Dictionary<string, ForecasterScore>();//排名结果
              
            try
            {
                string forecastNum = "", stationName = "";
        
                #region 晴雨预报正确率、一般降水、暴雨暴雪以上
                foreach (KeyValuePair<string, Dictionary<ForeSpanType, Dictionary<DateTime, int>>> pair in WaterAmountLevelScoreReport.RecordCount)
                {
                    forecastNum = GlobalFunction.SplitForecastNum(pair.Key, ref stationName);

                    ForecasterScore score = new ForecasterScore();
                    score.user = forecastNum;
                    score.station = stationName;

                    float MixPC = 0;
                    MixPC += WaterAmountLevelScoreReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD00_24].PC * 10;
                    MixPC += WaterAmountLevelScoreReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD24_48].PC  * 8;
                    MixPC += WaterAmountLevelScoreReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD48_72].PC  * 6;
                    MixPC += WaterAmountLevelScoreReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD72_96].PC  * 2;
                    MixPC += WaterAmountLevelScoreReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD96_120].PC  * 1;
                    MixPC /= 27;

                    score.PC = float.Parse(String.Format("{0:N2}", MixPC));
                   
                    float MixNormal = 0;
                    MixNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD00_24].TS  * 10;
                    MixNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD24_48].TS  * 8;
                    MixNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD48_72].TS  * 6;
                    MixNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD72_96].TS  * 2;
                    MixNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD96_120].TS  * 1;
                    MixNormal /= 27;

                    score.Normal = float.Parse(String.Format("{0:N2}", MixNormal));
                  
                    float MixNotNormal = 0;
                    MixNotNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD00_24].TS  * 10;
                    MixNotNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD24_48].TS  * 8;
                    MixNotNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD48_72].TS  * 6;
                    MixNotNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD72_96].TS * 2;
                    MixNotNormal += WaterAmountLevelScoreReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD96_120].TS  * 1;
                    MixNotNormal /= 27;

                    score.NotNormal = float.Parse(String.Format("{0:N2}", MixNotNormal));

                    ForecasterScoreList.Add(pair.Key, score);

                }
                #endregion

                #region 最高温及最低温预报准确率
                foreach (KeyValuePair<string, Dictionary<ForeSpanType, Dictionary<DateTime, int>>> pair in TempScoreReport.RecordCount)
                {

                    ForecasterScore score;
                    if (ForecasterScoreList.ContainsKey(pair.Key))
                        score = ForecasterScoreList[pair.Key];
                    else
                    {
                        score = new ForecasterScore();
                        forecastNum = GlobalFunction.SplitForecastNum(pair.Key, ref stationName);
                        score.user = forecastNum;
                        score.station = stationName;

                        ForecasterScoreList.Add(pair.Key, score);
                    }

                    score.RecordCount = TempScoreReport.ScheduleCount[pair.Key];//排班数

                    float MixMaxTt2 = 0;
                    MixMaxTt2 += TempScoreReport.MaxTempScore[pair.Key][ForeSpanType.FD00_24].Tt2 * 10;
                    MixMaxTt2 += TempScoreReport.MaxTempScore[pair.Key][ForeSpanType.FD24_48].Tt2 * 8;
                    MixMaxTt2 += TempScoreReport.MaxTempScore[pair.Key][ForeSpanType.FD48_72].Tt2 * 6;
                    MixMaxTt2 += TempScoreReport.MaxTempScore[pair.Key][ForeSpanType.FD72_96].Tt2 * 2;
                    MixMaxTt2 += TempScoreReport.MaxTempScore[pair.Key][ForeSpanType.FD96_120].Tt2 * 1;
                    MixMaxTt2 /= 27;

                    score.MaxTemp = float.Parse(String.Format("{0:N2}", MixMaxTt2));
                  
                    float MixMinTt2 = 0;
                    MixMinTt2 += TempScoreReport.MinTempScore[pair.Key][ForeSpanType.FD00_24].Tt2 * 10;
                    MixMinTt2 += TempScoreReport.MinTempScore[pair.Key][ForeSpanType.FD24_48].Tt2 * 8;
                    MixMinTt2 += TempScoreReport.MinTempScore[pair.Key][ForeSpanType.FD48_72].Tt2 * 6;
                    MixMinTt2 += TempScoreReport.MinTempScore[pair.Key][ForeSpanType.FD72_96].Tt2 * 2;
                    MixMinTt2 += TempScoreReport.MinTempScore[pair.Key][ForeSpanType.FD96_120].Tt2 * 1;
                    MixMinTt2 /= 27;

                    score.MinTemp = float.Parse(String.Format("{0:N2}", MixMinTt2));
                   
                }
                #endregion

                #region 24小时晴雨技巧值、24小时一般降水技巧值、24小时暴雨暴雪以上技巧值
                foreach (KeyValuePair<string, Dictionary<ForeSpanType, Dictionary<DateTime, int>>> pair in WaterAmountLevelSkillReport.RecordCount)
                {

                    ForecasterScore score;
                    if (ForecasterScoreList.ContainsKey(pair.Key))
                        score = ForecasterScoreList[pair.Key];
                    else
                    {
                        score = new ForecasterScore();
                        forecastNum = GlobalFunction.SplitForecastNum(pair.Key, ref stationName);
                        score.user = forecastNum;
                        score.station = stationName;

                        ForecasterScoreList.Add(pair.Key, score);
                    }

                    float Water_Skill = GlobalFunction.CalculateWaterSkill(WaterAmountLevelSkillReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD00_24].PC, WaterAmountLevelSkillStandardReport.WaterfallAmountWaterScore[pair.Key][ForeSpanType.FD00_24].PC);

                    score.FD24WaterSkill = float.Parse(String.Format("{0:N2}", Water_Skill));
                  
                    float Normal_Skill = GlobalFunction.CalculateWaterSkill(WaterAmountLevelSkillReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD00_24].TS, WaterAmountLevelSkillStandardReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.Normal][ForeSpanType.FD00_24].TS);

                    score.FD24NormalSkill = float.Parse(String.Format("{0:N2}", Normal_Skill));
                  
                    float NotNormal_Skill = GlobalFunction.CalculateWaterSkill(WaterAmountLevelSkillReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD00_24].TS, WaterAmountLevelSkillStandardReport.WaterfallLevelWaterScore[pair.Key][WaterfallLevel.NotNormal][ForeSpanType.FD00_24].TS);

                    score.FD24NotNormalSkill = float.Parse(String.Format("{0:N2}", NotNormal_Skill));
                   
                }
                #endregion

                #region 24小时最高温及最低温预报技巧值
                foreach (KeyValuePair<string, Dictionary<ForeSpanType, Dictionary<DateTime, int>>> pair in TempSkillReport.RecordCount)
                {

                    ForecasterScore score;
                    if (ForecasterScoreList.ContainsKey(pair.Key))
                        score = ForecasterScoreList[pair.Key];
                    else
                    {
                        score = new ForecasterScore();
                        forecastNum = GlobalFunction.SplitForecastNum(pair.Key, ref stationName);
                        score.user = forecastNum;
                        score.station = stationName;

                        ForecasterScoreList.Add(pair.Key, score);
                    }

                    //FD00_24最高温技巧值
                    float MaxT_Skill = GlobalFunction.CalculateTempSkill(TempSkillReport.MaxTempScore[pair.Key][ForeSpanType.FD00_24].Tt2, TempSkillStandardReport.MaxTempScore[pair.Key][ForeSpanType.FD00_24].Tt2);

                    score.FD24MaxTempSkill = float.Parse(String.Format("{0:N2}", MaxT_Skill));

                    //FD00_24最低温技巧值
                    float MinT_Skill = GlobalFunction.CalculateTempSkill(TempSkillReport.MinTempScore[pair.Key][ForeSpanType.FD00_24].Tt2, TempSkillStandardReport.MinTempScore[pair.Key][ForeSpanType.FD00_24].Tt2);

                    score.FD24MinTempSkill = float.Parse(String.Format("{0:N2}", MinT_Skill));
                   
                }
                #endregion


                foreach (KeyValuePair<string,ForecasterScore> pair in ForecasterScoreList)
                {
                    ForecasterScore score = pair.Value;

                    //if (score.user == "58044_7" || score.user == "58044_12")//score.user == "58044_1" ||
                    //    continue;
                    //由于 58248 镇江站已经取消，使用的是58252. 但是预报数据中一直使用的是58248,所以将镇江站手动修正为58252
                    score.user = score.user.Replace("58248", "58252");

                   
                    ScoreList.Add(score);
                }
               
            }
            catch (Exception ex)
            {
                Result.success = false.ToString();
                Result.msg = ex.ToString();
                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("memberReportScore");
                    exeStatus.SetMessage("Error", "执行出错");
                }
               
            }

            return ScoreList;
        }

        /// <summary>
        /// 计算综合分
        /// </summary>
        /// <param name="ForecasterScoreList"></param>
        private void CulculateComposite(List<ForecasterScore> ForecasterScoreList)
        {
            try
            {
                Dictionary<string, float> MaxValue = new Dictionary<string, float>();
                Dictionary<string, float> MinValue = new Dictionary<string, float>();
                MaxValue.Add("PC", -100); MinValue.Add("PC", -100);
                MaxValue.Add("Normal", -100); MinValue.Add("Normal", -100);
                MaxValue.Add("NotNormal", -100); MinValue.Add("NotNormal", -100);
                MaxValue.Add("MaxTemp", -100); MinValue.Add("MaxTemp", -100);
                MaxValue.Add("MinTemp", -100); MinValue.Add("MinTemp", -100);
                MaxValue.Add("FD24WaterSkill", -100); MinValue.Add("FD24WaterSkill", -100);
                MaxValue.Add("FD24NormalSkill", -100); MinValue.Add("FD24NormalSkill", -100);
                MaxValue.Add("FD24NotNormalSkill", -100); MinValue.Add("FD24NotNormalSkill", -100);
                MaxValue.Add("FD24MaxTempSkill", -100); MinValue.Add("FD24MaxTempSkill", -100);
                MaxValue.Add("FD24MinTempSkill", -100); MinValue.Add("FD24MinTempSkill", -100);

                

                //查找每一项的最大值和最小值
                foreach (ForecasterScore score in ForecasterScoreList)
                {
                    if (score.RecordCount == 0 || score.PC == 0)
                    {
                        if (score.PC == 0) score.PC = -99999;
                        if (score.Normal == 0) score.Normal = -99999;
                        if (score.NotNormal == 0) score.NotNormal = -99999;
                        if (score.MaxTemp == 0) score.MaxTemp = -99999;
                        if (score.MinTemp == 0) score.MinTemp = -99999;
                        if (score.FD24WaterSkill == 0) score.FD24WaterSkill = -99999;
                        if (score.FD24NormalSkill == 0) score.FD24NormalSkill = -99999;
                        if (score.FD24NotNormalSkill == 0) score.FD24NotNormalSkill = -99999;
                        if (score.FD24MaxTempSkill == 0) score.FD24MaxTempSkill = -99999;
                        if (score.FD24MinTempSkill == 0) score.FD24MinTempSkill = -99999;

                        continue;
                    }
                    
                    if (MaxValue["PC"] == -100)
                        MaxValue["PC"] = score.PC;
                    else if (score.PC > MaxValue["PC"])
                        MaxValue["PC"] = score.PC;
                    if (MinValue["PC"] == -100)
                        MinValue["PC"] = score.PC;
                    else if (score.PC < MinValue["PC"])
                        MinValue["PC"] = score.PC;


                    if (MaxValue["Normal"] == -100)
                        MaxValue["Normal"] = score.Normal;
                    else if (score.Normal > MaxValue["Normal"])
                        MaxValue["Normal"] = score.Normal;
                    if (MinValue["Normal"] == -100)
                        MinValue["Normal"] = score.Normal;
                    else if (score.Normal < MinValue["Normal"])
                        MinValue["Normal"] = score.Normal;

                    if (MaxValue["NotNormal"] == -100)
                        MaxValue["NotNormal"] = score.NotNormal;
                    else if (score.NotNormal > MaxValue["NotNormal"])
                        MaxValue["NotNormal"] = score.NotNormal;
                    if (MinValue["NotNormal"] == -100)
                        MinValue["NotNormal"] = score.NotNormal;
                    else if (score.NotNormal < MinValue["NotNormal"])
                        MinValue["NotNormal"] = score.NotNormal;


                    if (MaxValue["MaxTemp"] == -100)
                        MaxValue["MaxTemp"] = score.MaxTemp;
                    else if (score.MaxTemp > MaxValue["MaxTemp"])
                        MaxValue["MaxTemp"] = score.MaxTemp;
                    if (MinValue["MaxTemp"] == -100)
                        MinValue["MaxTemp"] = score.MaxTemp;
                    else if (score.MaxTemp < MinValue["MaxTemp"])
                        MinValue["MaxTemp"] = score.MaxTemp;


                    if (MaxValue["MinTemp"] == -100)
                        MaxValue["MinTemp"] = score.MinTemp;
                    else if (score.MinTemp > MaxValue["MinTemp"])
                        MaxValue["MinTemp"] = score.MinTemp;
                    if (MinValue["MinTemp"] == -100)
                        MinValue["MinTemp"] = score.MinTemp;
                    else if (score.MinTemp < MinValue["MinTemp"])
                        MinValue["MinTemp"] = score.MinTemp;


                    if (MaxValue["FD24WaterSkill"] == -100)
                        MaxValue["FD24WaterSkill"] = score.FD24WaterSkill;
                    else if (score.FD24WaterSkill > MaxValue["FD24WaterSkill"])
                        MaxValue["FD24WaterSkill"] = score.FD24WaterSkill;
                    if (MinValue["FD24WaterSkill"] == -100)
                        MinValue["FD24WaterSkill"] = score.FD24WaterSkill;
                    else if (score.FD24WaterSkill < MinValue["FD24WaterSkill"])
                        MinValue["FD24WaterSkill"] = score.FD24WaterSkill;


                    if (MaxValue["FD24NormalSkill"] == -100)
                        MaxValue["FD24NormalSkill"] = score.FD24NormalSkill;
                    else if (score.FD24NormalSkill > MaxValue["FD24NormalSkill"])
                        MaxValue["FD24NormalSkill"] = score.FD24NormalSkill;
                    if (MinValue["FD24NormalSkill"] == -100)
                        MinValue["FD24NormalSkill"] = score.FD24NormalSkill;
                    else if (score.FD24NormalSkill < MinValue["FD24NormalSkill"])
                        MinValue["FD24NormalSkill"] = score.FD24NormalSkill;


                    if (MaxValue["FD24NotNormalSkill"] == -100)
                        MaxValue["FD24NotNormalSkill"] = score.FD24NotNormalSkill;
                    else if (score.FD24NotNormalSkill > MaxValue["FD24NotNormalSkill"])
                        MaxValue["FD24NotNormalSkill"] = score.FD24NotNormalSkill;
                    if (MinValue["FD24NotNormalSkill"] == -100)
                        MinValue["FD24NotNormalSkill"] = score.FD24NotNormalSkill;
                    else if (score.FD24NotNormalSkill < MinValue["FD24NotNormalSkill"])
                        MinValue["FD24NotNormalSkill"] = score.FD24NotNormalSkill;

                    if (MaxValue["FD24MaxTempSkill"] == -100)
                        MaxValue["FD24MaxTempSkill"] = score.FD24MaxTempSkill;
                    else if (score.FD24MaxTempSkill > MaxValue["FD24MaxTempSkill"])
                        MaxValue["FD24MaxTempSkill"] = score.FD24MaxTempSkill;
                    if (MinValue["FD24MaxTempSkill"] == -100)
                        MinValue["FD24MaxTempSkill"] = score.FD24MaxTempSkill;
                    else if (score.FD24MaxTempSkill < MinValue["FD24MaxTempSkill"])
                        MinValue["FD24MaxTempSkill"] = score.FD24MaxTempSkill;


                    if (MaxValue["FD24MinTempSkill"] == -100)
                        MaxValue["FD24MinTempSkill"] = score.FD24MinTempSkill;
                    else if (score.FD24MinTempSkill > MaxValue["FD24MinTempSkill"])
                        MaxValue["FD24MinTempSkill"] = score.FD24MinTempSkill;
                    if (MinValue["FD24MinTempSkill"] == -100)
                        MinValue["FD24MinTempSkill"] = score.FD24MinTempSkill;
                    else if (score.FD24MinTempSkill < MinValue["FD24MinTempSkill"])
                        MinValue["FD24MinTempSkill"] = score.FD24MinTempSkill;
                }


                //计算综合分
                foreach (ForecasterScore score in ForecasterScoreList)
                {
                    if (score.RecordCount == 0 || score.PC == -99999)
                    {
                        score.Composite = -99999;
                        continue;
                    }

                    float PC = 0;
                    if (MaxValue["PC"] == MinValue["PC"])
                        PC = 1;
                    else
                        PC = (score.PC - MinValue["PC"]) / (MaxValue["PC"] - MinValue["PC"]);

                    float Normal = 0;
                    if (MaxValue["Normal"] == MinValue["Normal"])
                        Normal = 1;
                    else
                        Normal = (score.Normal - MinValue["Normal"]) / (MaxValue["Normal"] - MinValue["Normal"]);

                    float NotNormal = 0;
                    if (MaxValue["NotNormal"] == MinValue["NotNormal"])
                        NotNormal = 1;
                    else
                        NotNormal = (score.NotNormal - MinValue["NotNormal"]) / (MaxValue["NotNormal"] - MinValue["NotNormal"]);

                    float MaxTemp = 0;
                    if (MaxValue["MaxTemp"] == MinValue["MaxTemp"])
                        MaxTemp = 1;
                    else
                        MaxTemp = (score.MaxTemp - MinValue["MaxTemp"]) / (MaxValue["MaxTemp"] - MinValue["MaxTemp"]);

                    float MinTemp = 0;
                    if (MaxValue["MinTemp"] == MinValue["MinTemp"])
                        MinTemp = 1;
                    else
                        MinTemp = (score.MinTemp - MinValue["MinTemp"]) / (MaxValue["MinTemp"] - MinValue["MinTemp"]);

                    float FD24WaterSkill = 0;
                    if (MaxValue["FD24WaterSkill"] == MinValue["FD24WaterSkill"])
                        FD24WaterSkill = 1;
                    else
                        FD24WaterSkill = (score.FD24WaterSkill - MinValue["FD24WaterSkill"]) / (MaxValue["FD24WaterSkill"] - MinValue["FD24WaterSkill"]);

                    float FD24NormalSkill = 0;
                    if (MaxValue["FD24NormalSkill"] == MinValue["FD24NormalSkill"])
                        FD24NormalSkill = 1;
                    else
                        FD24NormalSkill = (score.FD24NormalSkill - MinValue["FD24NormalSkill"]) / (MaxValue["FD24NormalSkill"] - MinValue["FD24NormalSkill"]);

                    float FD24NotNormalSkill = 0;
                    if (MaxValue["FD24NotNormalSkill"] == MinValue["FD24NotNormalSkill"])
                        FD24NotNormalSkill = 1;
                    else
                        FD24NotNormalSkill = (score.FD24NotNormalSkill - MinValue["FD24NotNormalSkill"]) / (MaxValue["FD24NotNormalSkill"] - MinValue["FD24NotNormalSkill"]);

                    float FD24MaxTempSkill = 0;
                    if (MaxValue["FD24MaxTempSkill"] == MinValue["FD24MaxTempSkill"])
                        FD24MaxTempSkill = 1;
                    else
                        FD24MaxTempSkill = (score.FD24MaxTempSkill - MinValue["FD24MaxTempSkill"]) / (MaxValue["FD24MaxTempSkill"] - MinValue["FD24MaxTempSkill"]);

                    float FD24MinTempSkill = 0;
                    if (MaxValue["FD24MinTempSkill"] == MinValue["FD24MinTempSkill"])
                        FD24MinTempSkill = 1;
                    else
                        FD24MinTempSkill = (score.FD24MinTempSkill - MinValue["FD24MinTempSkill"]) / (MaxValue["FD24MinTempSkill"] - MinValue["FD24MinTempSkill"]);

                    double Composite = PC * 3 + Normal * 0.8 + NotNormal * 0.2 + MaxTemp * 2 + MinTemp * 2 + FD24WaterSkill * 3 + FD24NormalSkill * 0.8 + FD24NotNormalSkill * 0.2 + FD24MaxTempSkill * 2 + FD24MinTempSkill * 2;
                    
                    score.Composite = float.Parse(String.Format("{0:N2}", Composite));
                }

            }
            catch (Exception ex)
            {
                Result.success = false.ToString();
                Result.msg = ex.ToString();
                if (exeStatus != null)
                {
                    exeStatus.DeleteMessage("memberReportScore");
                    exeStatus.SetMessage("Error", "执行出错");
                }

            }

        }

        /// <summary>
        /// 根据预报综合得分进行排名，样本数>=平均样本数60%的预报员靠前排
        /// </summary>
        /// <param name="ForecasterScoreList"></param>
        /// <param name="FistEnd"></param>
        /// <param name="SecondEnd"></param>
        private void SortResult(List<ForecasterScore> ForecasterScoreList, ref int FistEnd, ref int SecondEnd)
        {

            List<ForecasterScore> frontList = new List<ForecasterScore>();
            List<ForecasterScore> lastList = new List<ForecasterScore>();
            List<ForecasterScore> zeroList = new List<ForecasterScore>();

            double avgCount = 0;
            double sumCount = 0;
            double zeroCount = 0;
            foreach (ForecasterScore Score in ForecasterScoreList)
            {
                sumCount += Score.RecordCount;
                if (Score.RecordCount == 0)
                    zeroCount += 1;
            }
            avgCount = sumCount * 1.0 / (ForecasterScoreList.Count - zeroCount);//平均样本数
            double lineCount = avgCount * Proportion;
            //double lineCount = avgCount * 0.67;//平均样本数的60%

            foreach (ForecasterScore Score in ForecasterScoreList)
            {
                if (Score.RecordCount >= lineCount)
                    frontList.Add(Score);//样本数>=平均样本数的60%,则靠前排
                else if (Score.RecordCount > 0)
                    lastList.Add(Score);
                else
                    zeroList.Add(Score);
            }

            ForecasterScoreList.Clear();

            frontList.Sort(new IndividualCompositeScore());
            for (int i = 1; i <= frontList.Count; i++)
            {
                frontList[i - 1].position = i;
                ForecasterScoreList.Add(frontList[i - 1]);
            }

            lastList.Sort(new IndividualCompositeScore());
            for (int i = 1; i <= lastList.Count; i++)
            {
                lastList[i - 1].position = i + frontList.Count;
                ForecasterScoreList.Add(lastList[i - 1]);
            }

            for (int i = 0; i < zeroList.Count; i++)
                ForecasterScoreList.Add(zeroList[i]);

            FistEnd = frontList.Count;
            SecondEnd = frontList.Count + lastList.Count;

        }

        #endregion
    }

   #region 用于JSON序列化

    public class ForecasterScore
    {
        public string user;
        public string station;
        public int position = 0;
        public float PC = 0;
        public float Normal = 0;
        public float NotNormal = 0;
        public float MaxTemp = 0;
        public float MinTemp = 0;
        public float FD24WaterSkill = 0;
        public float FD24NormalSkill = 0;
        public float FD24NotNormalSkill = 0;
        public float FD24MaxTempSkill = 0;
        public float FD24MinTempSkill = 0;
        public float Composite = 0;
        public int RecordCount = 0;

        //public float FD24PC=0;
        //public float FD24Maxt = 0;
        //public float FD24Mint = 0;
        //public float FD24Normal = 0;
        //public float FD48PC = 0;
        //public float FD48Maxt = 0;
        //public float FD48Mint = 0;
        //public float FD48Normal = 0;

        public ForecasterScore(string Name, string Station, int Position, float pc, float normal, float notmormal, float maxtemp, float mintemp, float fd24waterskill, float fd24normalskill, float fd24notnormalskill, float fd24maxtempskill, float fd24mintempskill, int recordcount)
        {
            user = Name;
            station = Station;
            position = Position;
            PC = pc;
            Normal = normal;
            NotNormal = notmormal;
            MaxTemp = maxtemp;
            MinTemp = mintemp;
            FD24WaterSkill = fd24waterskill;
            FD24NormalSkill = fd24normalskill;
            FD24NotNormalSkill = fd24notnormalskill;
            FD24MaxTempSkill = fd24maxtempskill;
            FD24MinTempSkill = fd24mintempskill;
            RecordCount = recordcount;
            //everyMonthRecordCount = EveryMonthRecordCount;
        }

        public ForecasterScore()
        { }
    }

    public class ForecasterRankResult
    {
        public string success = true.ToString();
        public string msg = "";
        public Dictionary<string, object> result = new Dictionary<string, object>();

        public ForecasterRankResult()
        {
            result.Add("first_end", 0);
            result.Add("second_end", 0);
            result.Add("data", new List<object>());
        }
    }

     #endregion
}
